package com.ccsoft.zknote.service.impl;

import com.ccsoft.zknote.dao.IThingDao;
import com.ccsoft.zknote.pojo.Thing;
import com.ccsoft.zknote.pojo.User;
import com.ccsoft.zknote.pojo.system.BusinessException;
import com.ccsoft.zknote.service.IThingService;
import com.ccsoft.zknote.util.SystemUtils;
import com.mybatisflex.core.query.QueryWrapper;
import com.mysql.cj.x.protobuf.MysqlxCursor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import static com.ccsoft.zknote.pojo.table.Tables.THING;

/**
 * @author chanchaw
 * @create 2023-07-12 18:38
 */
@Service
public class ThingServiceImpl implements IThingService {
    @Autowired
    private IThingDao dao;
    @Autowired
    private SystemUtils systemUtils;
    @Override
    public List<Thing> getUserThings(Integer userId) {
        userId = Optional.ofNullable(userId).orElse(0);
        if(userId == 0) throw new BusinessException("没有获得用户ID，无法查询其小记！");

        ArrayList<Integer> statusList = new ArrayList<>();
        statusList.add(-1);statusList.add(0);
        QueryWrapper queryWrapper = QueryWrapper.create()
                .where(THING.USER_ID.eq(userId))
                .and(THING.STATUS.notIn(statusList))
                .orderBy(THING.FINISHED.asc(),THING.TOP.desc(),THING.UPDATE_TIME.desc())
                ;
        return dao.selectListByQuery(queryWrapper);
    }

    @Override
    public List<Thing> getUserThings8Token(String token){
        User redisTokenUser = systemUtils.getRedisTokenUser(token);
        if(redisTokenUser == null) throw new BusinessException("未能根据token获取用户信息，未登录或者登录已失效！");
        Integer id = Optional.ofNullable(redisTokenUser.getId()).orElse(0);
        return getUserThings(id);
    }

    /**
     * 在当前最大的数字上累加1，保证当前被操作置顶的数据
     * 一定在第一位上
     * @param top true表示设置位置顶
     * @param id thing.id
     * @return 置顶成功则返回 true
     */
    @Override
    public Boolean setTop(Boolean top, Integer id){
        QueryWrapper queryWrapper = QueryWrapper.create()
                .where(THING.ID.eq(id))
                .and(THING.STATUS.eq(1));
        Thing thing = dao.selectOneByQuery(queryWrapper);
        if(thing == null) throw new BusinessException("没有找到主键" +id+"的小记！" );

        if(top){
            Integer newTop = getNewTop();
            thing.setTop(newTop);
        }else{
            thing.setTop(0);
        }
        dao.update(thing);
        return true;
    }

    /**
     * 获取下一个置顶动作中 top 的值
     * @return
     */
    private Integer getNewTop(){
        QueryWrapper queryWrapper = QueryWrapper.create()
                .orderBy(THING.TOP.desc())
                .limit(1);
        Thing thing = dao.selectOneByQuery(queryWrapper);
        if(thing == null) return 1;
        return thing.getTop() + 1;
    }

    @Override
    public Boolean delete8Id(Integer id){
        return delete8Id(id,0);
    }

    @Override
    public Boolean delete8Id(Integer id, Boolean thoroughly){
        Integer status = thoroughly ? -1 : 0;
        return delete8Id(id, status);
    }

    private Boolean delete8Id(Integer id,Integer status){
        QueryWrapper queryWrapper = QueryWrapper.create()
                .where(THING.ID.eq(id))
                .and(THING.STATUS.eq(1))
                ;
        Thing thing = dao.selectOneByQuery(queryWrapper);
        if(thing == null) return false;
        thing.setStatus(status);
        dao.update(thing);
        return true;
    }

    @Override
    public Thing selectByPrimaryKey(Integer id){
        return dao.selectOneById(id);
    }

    @Override
    public Thing insertSelective(Thing record) {
        record.setTime(new Date());
        check4Save(record);

        int i = 0;
        try {
            i = dao.insertSelective(record);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException("新增小记出现异常！");
        }
        if(i != 1) throw new BusinessException("新增小记失败！");
        return record;
    }

    @Override
    public Thing updateSelective(Thing record){
        dao.update(record);
        return record;
    }

    // 保存前调用本方法
    private void check4Save(Thing record){
        if(record == null) throw new BusinessException("空数据不可保存！");
        Integer userId = Optional.ofNullable(record.getUserId()).orElse(0);
        if(userId.equals(0)) throw new BusinessException("没有设置用户，无法保存！");
        String title = Optional.ofNullable(record.getTitle()).orElse("");
        if(title.length() == 0) throw new BusinessException("标题不可为空！");
        String content = Optional.ofNullable(record.getContent()).orElse("");
        if(content.length() == 0) throw new BusinessException("待办事项不可为空！");
    }

    /**
     * 获取e.printStackTrace() 的具体信息，赋值给String 变量，并返回
     *
     * @param e
     *            Exception
     * @return e.printStackTrace() 中 的信息
     */
    public static String getStackTraceInfo(Exception e) {
        StringWriter sw = null;
        PrintWriter pw = null;
        try {
            sw = new StringWriter();
            pw = new PrintWriter(sw);
            e.printStackTrace(pw);//将出错的栈信息输出到printWriter中
            pw.flush();
            sw.flush();

            return sw.toString();
        } catch (Exception ex) {

            return "发生错误";
        } finally {
            if (sw != null) {
                try {
                    sw.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if (pw != null) {
                pw.close();
            }
        }

    }

    @Override
    public Thing insertSelective(Thing record, String token){
        User redisTokenUser = systemUtils.getRedisTokenUser(token);
        record.setUserId(redisTokenUser.getId());
        return insertSelective(record);
    }

    /**
     * 搜索模糊查询的小记
     * @param search 搜索标题或者标签（title,tags）
     * @param finished 1已完成的，0未完成的，
     * @param token 用户token
     * @return 返回模糊查询得到的小记集合
     */
    @Override
    public List<Thing> search(String search, Integer finished, String token){
        token = Optional.ofNullable(token).orElse("");
        search = Optional.ofNullable(search).orElse("");
        if(token.length() == 0) throw new BusinessException("请登录后再尝试本操作！");

        // 构建查询SQL
        User user = systemUtils.getRedisTokenUser(token);
        QueryWrapper queryWrapper = QueryWrapper.create().where(THING.USER_ID.eq(user.getId())).and(THING.STATUS.eq(1));
        if(search.length() > 0){
            queryWrapper.and(THING.TITLE.like(search).or(THING.TAGS.like(search)));
        }
        if(finished != null) queryWrapper.and(THING.FINISHED.eq(finished));
        queryWrapper.orderBy(THING.FINISHED.asc(),THING.TOP.desc(),THING.UPDATE_TIME.desc());
        List<Thing> things = dao.selectListByQuery(queryWrapper);
        return things;
    }

    @Override
    public List<Thing> test1(String keywords){
        List<Thing> things = dao.test1(keywords);
        System.out.println(things);
        return things;
    }
}
